package jonaVisual;

import java.util.Vector;

import Jona.ArgObject;
import Jona.Conditional;
import Jona.Negation;
import Jona.Theory;
import java.awt.*;
import java.awt.geom.Rectangle2D;

public class VOTreeMaker2 {
	private VisualObject[] vo1;
	
	private VisualObject[] record;
	private boolean recordVOs = false;
	
	private final int xOffset = 5;
	private final int yOffset = 5;
	
	//should be the same as in VisualArgobject..
	private static int text_indentX = 42;
	private static int spacing_X = 10;
	private int statementIndex = 1;
	private final int minimumstatementHeight = 40;
	private int nextRow = 0;
	private int initIndent = 0;
	private int horizontalSpacer = 25;
	private int nextRowIndent = 5; //actually 5..
	private int spacer_horizontal = 5;
	private int minX = 0;
	
	public VisualObject[] makeTreeFromTheory(Theory t1,Graphics2D g2)
	{
		System.out.println("#################################");
		long time = System.currentTimeMillis();
		ArgObject[] roots = t1.giveRootStatements();
		ArgObject[] statements = t1.getStatements();
		vo1 = null;		
		if(roots != null)
		{
			if(roots.length > 0)
			{
				for(int i =0; i < roots.length ; i++)
				{
					Parameters p = new Parameters();
					p.g2 = g2;
					p.root = null;
					p.pointTo= new Point(xOffset,yOffset);
					p.statements = statements;
					p.statement = roots[i];
					p.horizontal = true;
					p.first = true;
					makeTreeForStatement(p);
					nextRow +=10;
				}
		
			
			
			
			}
		}
		if(vo1 != null)
		{
			for(int i =0; i < vo1.length; i++)
			{
				if(vo1[i] instanceof VisualArgObject)
				{
					if(minX > vo1[i].getBounds().x)	minX = vo1[i].getBounds().x;
				}
			}
			if(minX < 0)
			{
				minX-=10;
				for(int i =0; i < vo1.length;i++)
				{
					vo1[i].translate(-minX,0);
				}
			}								
		}
		
		System.out.println("made Tree in : " + (System.currentTimeMillis() - time) + " millisecs.");	
		System.out.println("#################################");
		return vo1;
	}

	private void makeTreeForStatement(Parameters p)
	{
		// go to depth first and then return...
		//                 *******
		//                 *     *
		//                 *X*X***
		//					| | \----------\ 
		//       /----------/ |			   |
		//		 |            | 		   |
		//  	 |            |			   |	
		//    *******      *******  	*******
		//	  *     *      *     *		*     *
		//    *******	   *******		*******
		
		ArgObject activeStatement =p.statement;
		ArgObject root = p.root;
		boolean negate = p.negate;
		
		if(activeStatement instanceof Conditional)
		{
			//conditional...
			ArgObject[][] attackSupport = getAttackerAndSupporters(activeStatement,p.statements );
			//make this statement the root.
			p.root= activeStatement;
			int total =  attackSupport[0].length + attackSupport[1].length;
			Conditional c1 = (Conditional)activeStatement;
			ArgObject[] antecedent = c1.getAntecedents();
			
			if(!p.horizontal)
			{	
				//verticaal
				if(root instanceof Conditional)
				{
					p.connectToConditional = true;
					//System.out.println(" done!!");
				}
				else
				{
					p.connectToConditional = false;
				}
				if(p.connectToConditional && !p.first)
				{
					if(negate)
					{
						p.pointTo.x -= 25;
					}
					else
					{
						p.pointTo.x +=25;
					}
				}
				else
				{
					p.first = false;
				}
				
				int shift = (total * horizontalSpacer);				
				if(negate) shift= -shift;
				Point p1 = p.pointTo;
				p.pointTo = new Point(p.pointTo.x + shift, p.pointTo.y);
				p.arrowLength = Math.abs(shift);
				Point p2 = new Point(p1.x + shift,yOffset + nextRow+20);
				for(int i =0; i < antecedent.length ; i++)
				{
					p.statement=antecedent[i];
					makeTreeForStatement(p.giveCopy());	
				}
						
				//p.pointTo = new Point(p2.x - horizontalSpacer,p2.y);
				p.pointTo = p2;
				int littleShift = horizontalSpacer;
				if(negate) littleShift = - littleShift;
				p.arrowLength = 0;
				p.horizontal = true;
				for(int i= 0; i < attackSupport[0].length;i++)
				{
					p.statement=attackSupport[0][i];
					makeTreeForStatement(p.giveCopy());	
					p.pointTo = new Point(p.pointTo.x - littleShift,p.pointTo.y);
				}
				for(int i= 0; i < attackSupport[1].length;i++)
				{
					p.statement=attackSupport[1][i];
					makeTreeForStatement(p.giveCopy());	
					p.pointTo = new Point(p.pointTo.x -  littleShift,p.pointTo.y);
				}
			}
			else
			{
				//horizontaal
				if(root instanceof Conditional)
				{
					p.connectToConditional = true;
					//System.out.println(" done!!");
				}
				else
				{
					p.connectToConditional = false;
				}
				p.horizontal = false;
			
				for(int i= 0; i < attackSupport[0].length;i++)
				{
					p.statement=attackSupport[0][i];
					
					//p.pointTo = new Point(p.pointTo.x-50,p.pointTo.y);
					makeTreeForStatement(p.giveCopy());	
				
				}
				
				for(int i= 0; i < attackSupport[1].length;i++)
				{
					p.statement=attackSupport[1][i];
			
					makeTreeForStatement(p.giveCopy());	
				}	
				p.horizontal = true;
				
				for(int i =0; i < antecedent.length ; i++)
				{
					p.statement=antecedent[i];
					p.root = activeStatement;
					makeTreeForStatement(p.giveCopy());	
				}

				
			}
		}
		else
		{
			//statement...
			ArgObject[][] attackSupport = getAttackerAndSupporters(activeStatement,p.statements );
			//make this statement the root.
			int total = attackSupport[0].length + attackSupport[1].length;
			p.root= activeStatement;
			int indent = p.indent;
			int index = 0;				
			//activeStatement.setText("#" + statementIndex + "#" + activeStatement.getText());
			statementIndex++;
			VisualArgObject va1 = new VisualArgObject(activeStatement);
			//va1.setRecursive(found);
			int statementHeight = 0;
			String data[] = activeStatement.getText().split("\n");
			double width1 =100;
			if(data.length > 1)
			{
				Rectangle2D r2 = null;
				String line="";
				double dumx =0;
				for(int i =0; i < data.length; i++)
				{
					line = data[i];
					r2 = p.g2.getFontMetrics().getStringBounds(line,0,line.length(),p.g2);	
					dumx = r2.getWidth();
					if(dumx > width1) width1 = dumx;
				}
				statementHeight = ((data.length - 1) * 10) + 20;
			}
			else
			{
				String line = activeStatement.getText();
				Rectangle2D r2 = null;
				r2 = p.g2.getFontMetrics().getStringBounds(line,0,line.length(),p.g2);	
				double dumx =0;
				dumx = r2.getWidth();
				if(dumx > width1) width1 = dumx;
			}
		
			
			if(statementHeight < minimumstatementHeight) statementHeight = minimumstatementHeight;
		
			if(width1 < (total * horizontalSpacer) ) width1 = (total * horizontalSpacer);
			//int xpos = xOffset + p.indent ;
				
			int xpos = p.pointTo.x;
			if(negate)
				xpos -= (int)(width1 + spacing_X + text_indentX + spacer_horizontal);
			if(p.connectToConditional)
			{
				if(negate)
				{
					xpos -=horizontalSpacer;
				}
				else
				{
					xpos+=horizontalSpacer;
				}
			}
			va1.setRectangle(new Rectangle( xpos ,yOffset + nextRow,(int)width1,statementHeight));	
			
			//p.indent +=(int)(width1 + spacing_X + text_indentX + spacer_horizontal);
			//int midX =  (xOffset + p.indent) + (int)(width1 /2);
			//p.topMidStatement = new Point(midX,yOffset + nextRow);
			addVisualObject(va1);	
			int x1 = xpos;	
			Arrow a1 = new Arrow((Conditional)root);
			if(root instanceof Conditional)
			{					
				if(negate)
				{
					x1 = xpos + (int)(width1 + spacing_X + text_indentX);
				}			
				a1.addPoint(x1,yOffset + nextRow + 20);
				
				if(!p.connectToConditional)
				{		
					if(p.horizontal)
					{
						if(negate)
						{
							a1.addPoint(x1 + 15, yOffset + nextRow + 20);
							a1.addPoint(x1 + 15,p.pointTo.y);
							//a1.addPoint(x1 + 15,p.pointTo.y);	
						}
						else
						{
							a1.addPoint(x1 - 15, yOffset + nextRow + 20);
							a1.addPoint(x1 - 15,p.pointTo.y);	
						}
					}
					else
					{
						a1.addPoint(x1 - 100,yOffset + nextRow + 20);
					}
				}
				else
				{
					if(!p.horizontal)
					{
						if(negate)
							a1.addPoint(x1+(15 + horizontalSpacer + p.arrowLength),yOffset + nextRow + 20);
						else
							a1.addPoint(x1-(15 + horizontalSpacer + p.arrowLength),yOffset + nextRow + 20);
					}
					else
					{
						if(negate)
						{
							a1.addPoint(x1 + 15,yOffset + nextRow + 20 );
							a1.addPoint(x1 + 15,p.pointTo.y);
						}
						else
						{
							a1.addPoint(x1 - 15,yOffset + nextRow + 20 );
							a1.addPoint(x1 - 15,p.pointTo.y);
						}
					}
					
				}
				addVisualObject(a1);	
			}
			
				
			Point pointTo = new Point(xpos + 10,yOffset + nextRow +statementHeight);
			nextRow+= (nextRowIndent + statementHeight);
			int nextRow1 = nextRow;
			//int intitalIndent = p.indent;
			//int indentx = p.indent;
			p.horizontal = true;
			p.first = true;
			p.arrowLength =0;
			int startIndex =  vo1.length;
			
			for(int i= 0; i < attackSupport[0].length;i++)
			{
				p.negate = true;
				//indentx += horizontalSpacer;
				//p.indent=indentx;
				p.pointTo = pointTo;
				p.statement=attackSupport[0][i];
				makeTreeForStatement(p.giveCopy());	
				pointTo = new Point(pointTo.x + horizontalSpacer, pointTo.y);
			}
			int oldNextRow = nextRow;
			
			if(attackSupport[1].length > 0)
				nextRow = nextRow1;
			//indentx = p.indent + (horizontalSpacer * attackSupport[1].length) + (horizontalSpacer *4);
			pointTo = new Point(pointTo.x + (horizontalSpacer * attackSupport[1].length + horizontalSpacer), pointTo.y);
			for(int i= 0; i < attackSupport[1].length;i++)
			{
				p.negate = false;
				//indentx -= horizontalSpacer;
				//p.indent = indentx;
				p.pointTo = pointTo;
				p.statement=attackSupport[1][i];
				makeTreeForStatement(p.giveCopy());	
				pointTo = new Point(pointTo.x - horizontalSpacer, pointTo.y);
			}
			if(nextRow < oldNextRow) nextRow = oldNextRow;
			//p.indent = intitalIndent;
			//p.indent = indentx;
			//System.out.println("FOUND:" + activeStatement.getText());
			//recordVOs =false;
			int endIndex =  vo1.length;
			
			if((endIndex - startIndex) > 0 && root != null)
			{
				if(negate)
				{
					//is negated thingy...
					int maxX = x1;
					for(int i =(startIndex); i < (endIndex);i++)
					{
						if(vo1[i] instanceof VisualArgObject)
						{
							Rectangle r1 = vo1[i].getBounds();
							if((r1.x + r1.width) > maxX) maxX = (r1.x + r1.width);
							//if((r1.x + r1.width) > maxX) maxX = r1.x + r1.width;
						}
					}
					if(maxX > x1);
					{
						maxX+= 50;//va1.getRectangle().width;
						for(int i =(startIndex); i < (endIndex);i++)
						{
							vo1[i].translate((x1 - maxX),0);
						}
						va1.translate((x1 - maxX ),0);
						a1.translatefirst((x1 - maxX ),0);
						//System.out.println("translated");
					}
				}
				else
				{
					//find minx...
					int minx = x1;
					//int maxX = x1;
					for(int i =(startIndex); i < (endIndex);i++)
					{
						if(vo1[i] instanceof VisualArgObject)
						{
							Rectangle r1 = vo1[i].getBounds();
							if(r1.x < minx) minx = r1.x;
							//if((r1.x + r1.width) > maxX) maxX = r1.x + r1.width;
						}
					}
					if(minx < x1);
					{
						for(int i =(startIndex); i < (endIndex);i++)
						{
							vo1[i].translate((x1 - minx),0);
						}
						va1.translate((x1 - minx),0);
						a1.translatefirst((x1 - minx),0);
						//Point p2 = a1.getLastInsertedPoint();
						//p2.translate((minx - x1),0);
					}
					//if(maxX > x1) System.out.println("FOUNDFOUNDFOUND2!!");
					//System.out.println("done " + activeStatement.getText() + " " +minx + " " + x1 );
				}
			}
			
			//if(minX > va1.getRectangle().x) minX = va1.getRectangle().x;
		}		
	}
			
	
	
	private ArgObject[][] getAttackerAndSupporters(ArgObject root, ArgObject[] statements)
	{
		ArgObject[][] attacksupport = new ArgObject[2][0];
		//0 is attackers
		//1 is supporters
		for(int i =0 ; i < statements.length; i++)
		{
			if(statements[i] instanceof Conditional)
			{
				Conditional c1 = (Conditional)statements[i];
				if(c1.getConsequent() instanceof Negation)
				{
					Negation n1 = (Negation)c1.getConsequent();
					if(n1.getNegation() == root)
						attacksupport[0] = addToList(attacksupport[0],c1);	
				}
				else
				{
					if(c1.getConsequent() == root)
						attacksupport[1] = addToList(attacksupport[1],c1);
				}
			}
		}
		
		return attacksupport;
	}
	
	protected ArgObject [] addToList(ArgObject [] list, ArgObject element) {
		if(list == null)  
		{
			list = new ArgObject[1];
			list[0] = element;
			return list;
		}
		else
		{
			int i, length;
			ArgObject [] temp;
			
			length = list.length;
			
			temp = new ArgObject[length+1];
			for (i = 0; i < length; ++i) {
				if (list[i] == element) {
					return list;
				}
				temp[i] = list[i];
			}
			temp[length] = element;
			return temp;
		}
	}
	
	protected boolean findInList(ArgObject[] list, ArgObject element)
	{
		boolean found = false;
		int i =0;
		while(!found && i < list.length)
		{
			if(list[i]== element) found = true;
			i++;
		}
		return found;
	}	
	
	private void addVisualObject(VisualObject vo2)
	{
		if(vo1 == null)
		{			
			vo1 = new VisualObject[1];
			vo1[0] = vo2;				
		}
		else
		{
			VisualObject[] dum = new VisualObject[vo1.length + 1];
			for(int i =0; i < vo1.length;i++)
				dum[i] = vo1[i];
			dum[vo1.length] = vo2;
			vo1 = dum;
		}	
	}		
}

class Parameters
{
	public VisualObject[] record=null;
	public boolean first= true;
	public int arrowLength =0;
	public boolean horizontal = true;
	public boolean connectToConditional = false;
    public boolean negate = false;
	public Point pointTo = null;
	public ArgObject root = null;
	public ArgObject statement = null;
	public ArgObject[] statements = null;
	public Vector done = new Vector(5);
	public Graphics2D g2 = null;
	public int indent = 0;
	public Parameters()
	{
		
	}
	
	
	public Parameters giveCopy()
	{
		Parameters p1 = new Parameters();
		p1.record = record;
		p1.first = first;
		p1.arrowLength = arrowLength;
		p1.horizontal = this.horizontal;
		p1.connectToConditional  = this.connectToConditional;
		p1.negate = negate;
		p1.pointTo = new Point(pointTo);
		p1.root = this.root;
		p1.statements = statements;
		p1.statement =this.statement;
		p1.done = new Vector(done);
		p1.g2 = g2;
		p1.indent = indent;
		return p1;
	}
}

